package com.smart.milvus.bean;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

@Slf4j
public class DefaultSpElExecutor implements BeanFactoryAware {
    private final static ExpressionParser PARSER = new SpelExpressionParser();
    private final static TemplateParserContext PARSER_CONTEXT = new TemplateParserContext();
    private final static String DEFAULT_END = "}";
    private final static String DEFAULT_VAL_START = "#{";
    private BeanFactory BEAN_FACTORY;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.BEAN_FACTORY = beanFactory;
    }

    public <T> T exec(String name, Class<T> clazz) {
        StandardEvaluationContext evaluationContext = genEvaluationContext();
        try {
            return PARSER.parseExpression(resolve(DEFAULT_VAL_START + name + DEFAULT_END),
                    PARSER_CONTEXT).getValue(evaluationContext, clazz);
        } catch (Exception ignored) {
            log.error("Failed to resolve name: " + name, ignored);
        }
        return null;
    }

    private StandardEvaluationContext genEvaluationContext() {
        StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
        evaluationContext.setBeanResolver(new BeanFactoryResolver(BEAN_FACTORY));
        return evaluationContext;
    }

    private String resolve(String value) {
        if (BEAN_FACTORY != null && BEAN_FACTORY instanceof ConfigurableBeanFactory) {
            return ((ConfigurableBeanFactory) BEAN_FACTORY).resolveEmbeddedValue(value);
        }
        return value;
    }
}
